package com.china.school;

import com.china.school.pojo.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;


@Aspect
@ComponentScan({"com.china.school"}) //<context:component-scan base-package="xx"/>
//@EnableAspectJAutoProxy(proxyTargetClass = true)
@EnableAspectJAutoProxy
//@EnableSpringConfigured
public class AspectTest {

    /**
     连接点：所有方法
     切入点：满足表达式的方法
     增强处理
     织入： 将增强处理添加到目标对象中，并创建一个增强对象的过程叫做织入
     目标对象： target 被增强的对象
     代理对象： this 代理对象
     切面： 即增强处理+切入点组成的类 @Aspect修饰
     advisor： 一对 增强处理+切入点

     1 当代理的类不是接口时，SpringAop自动切换为cglib代理
     2 当代理的类为接口时，默认jdk动态代理，但是可以通过指定proxyTargetClass = true，从而强制使用动态代理
     3 下面12种定义切点的方式
     execution: 用于匹配方法执行的连接点。这是在使用Spring AOP时要使用的主要切点指定器。
     within: 将匹配限制在某些类型内的连接点（使用Spring AOP时，执行在匹配类型内声明的方法）。
     this: 将匹配限制在连接点（使用Spring AOP时方法的执行），其中bean引用（Spring AOP代理）是给定类型的实例。
     target: 将匹配限制在连接点（使用Spring AOP时方法的执行），其中目标对象（被代理的应用程序对象）是给定类型的实例。
     args: 将匹配限制在连接点（使用Spring AOP时方法的执行），其中参数是给定类型的实例。
     @target: 限制匹配到连接点（使用Spring AOP时方法的执行），其中执行对象的类有一个给定类型的注解。
     @args: 将匹配限制在连接点（使用Spring AOP时方法的执行），其中实际传递的参数的运行时类型有给定类型的注解。
     @within: 将匹配限制在具有给定注解的类型中的连接点（使用Spring AOP时，执行在具有给定注解的类型中声明的方法）。
     @annotation: 将匹配限制在连接点的主体（Spring AOP中正在运行的方法）具有给定注解的连接点上。
     bean(testService)
     @pointcut(com.china.shcool.Test.a())
     逻辑组合 && || !


     Spring会把五个注解解析为对应的Advice类：
     1. @Before：AspectJMethodBeforeAdvice，实际上就是一个MethodBeforeAdvice
     2. @AfterReturning：AspectJAfterReturningAdvice，实际上就是一个AfterReturningAdvice
     3. @AfterThrowing：AspectJAfterThrowingAdvice，实际上就是一个MethodInterceptor
     4. @After：AspectJAfterAdvice，实际上就是一个MethodInterceptor
     5. @Around：AspectJAroundAdvice，实际上就是一个MethodInterceptor


     */

    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AspectTest.class);
        User user = ctx.getBean(User.class);
        user.eat();
        user.aaaa();

    }


     @Before("execution(* com.china.school.pojo.User.eat())")
    public void before(){
        System.out.println("------before---------");
    }

    @After("execution(* com.china.school.pojo.User.eat())")
    public void after(){
        System.out.println("------after---------无论是否异常，都会执行");
    }


    /**

     ProceedingJoinPoint is only supported for around advice
     */
//    @Around("execution(* com.china.school.pojo.User.eat())")
    @Around("@annotation(anno)")
    public void around(ProceedingJoinPoint joinPoint ,MyAnno anno) throws Throwable {
        System.out.println("------around---前------" + joinPoint.getClass());

        if(joinPoint.getArgs().length == 0){

            joinPoint.proceed( );
        }else {
            joinPoint.proceed(  );

        }
        System.out.println("------around-----后----" + joinPoint.getClass());

    }


    @AfterReturning("execution(* com.china.school.pojo.User.eat())")
    public void returning( ){
        System.out.println("------after-returning---------方法正常结束执行");
    }
    @AfterThrowing("execution(* com.china.school.pojo.User.eat())")
    public void throwing(){
        System.out.println("------after-throwing---------抛出异常才执行");
    }








}
